// Copyright 2022 liangzhuzhi2020@gmail.com, https://github.com/liang-zhu-zi/esp32-thingsboard-mqtt-client
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// ThingsBoard Client MQTT helper (TBCMH) API

#ifndef _TBC_MQTT_HELPER_H_
#define _TBC_MQTT_HELPER_H_

#include <stdint.h>
#include <stdbool.h>

#include "cJSON.h"

#include "tbc_utils.h"
#include "tbc_transport_config.h"

#ifdef __cplusplus
extern "C" {
#endif

//==== Data type ==============================================================

/**
 * ThingsBoard MQTT Client Helper handle
 */
typedef struct tbcmh_client *tbcmh_handle_t;

/**
 * ThingsBoard MQTT Client Helper value, for example: data point, attributes
 */
typedef cJSON tbcmh_value_t;

/**
 * ThingsBoard MQTT Client Helper rpc params
 */
typedef cJSON tbcmh_rpc_params_t;

/**
 * ThingsBoard MQTT Client Helper rpc results
 */
typedef cJSON tbcmh_rpc_results_t;
  
/**
 * ThingsBoard MQTT Client Helper provision params
 */
typedef cJSON tbcmh_provision_params_t;

/**
 * ThingsBoard MQTT Client Helper provision results
 */
typedef cJSON tbcmh_provision_results_t;

typedef enum tbc_provision_type
{
  TBC_PROVISION_TYPE_NONE = 0,
  TBC_PROVISION_TYPE_SERVER_GENERATES_CREDENTIALS,             // Credentials generated by the ThingsBoard server
  TBC_PROVISION_TYPE_DEVICE_SUPPLIES_ACCESS_TOKEN,             // Devices supplies Access Token
  TBC_PROVISION_TYPE_DEVICE_SUPPLIES_BASIC_MQTT_CREDENTIALS,   // Devices supplies Basic MQTT Credentials
  TBC_PROVISION_TYPE_DEVICE_SUPPLIES_X509_CREDENTIALS          // Devices supplies X.509 Certificate
} tbc_provision_type_t;

/*
 | Provisioning request  | Parameter              | Description                                                                    | Credentials generated by <br/>the ThingsBoard server | Devices supplies<br/>Access Token | Devices supplies<br/>Basic MQTT Credentials | Devices supplies<br/>X.509 Certificate |
 |-----------------------|------------------------|--------------------------------------------------------------------------------|------------------------------------------------------|-----------------------------------|---------------------------------------------|----------------------------------------|
 |                       | deviceName             | Device name in ThingsBoard.                                                    | (O) DEVICE_NAME                                      | (O) DEVICE_NAME                   | (O) DEVICE_NAME                             | (O) DEVICE_NAME                        |
 |                       | provisionDeviceKey     | Provisioning device key, you should take it from configured device profile.    | (M) PUT_PROVISION_KEY_HERE                           | (M) PUT_PROVISION_KEY_HERE        | (M) PUT_PROVISION_KEY_HERE                  | (M) PUT_PROVISION_KEY_HERE             |
 |                       | provisionDeviceSecret  | Provisioning device secret, you should take it from configured device profile. | (M) PUT_PROVISION_SECRET_HERE                        | (M) PUT_PROVISION_SECRET_HERE     | (M) PUT_PROVISION_SECRET_HERE               | (M) PUT_PROVISION_SECRET_HERE          |
 |                       | credentialsType        | Credentials type parameter.                                                    |                                                      | (M) ACCESS_TOKEN                  | (M) MQTT_BASIC                              | (M) X509_CERTIFICATE                   |
 |                       | token                  | Access token for device in ThingsBoard.                                        |                                                      | (M) DEVICE_ACCESS_TOKEN           |                                             |                                        |
 |                       | clientId               | Client id for device in ThingsBoard.                                           |                                                      |                                   | (M) DEVICE_CLIENT_ID_HERE                   |                                        |
 |                       | username               | Username for device in ThingsBoard.                                            |                                                      |                                   | (M) DEVICE_USERNAME_HERE                    |                                        |
 |                       | password               | Password for device in ThingsBoard.                                            |                                                      |                                   | (M) DEVICE_PASSWORD_HERE                    |                                        |
 |                       | hash                   | Public key X509 hash for device in ThingsBoard.                                |                                                      |                                   |                                             | (M) MIIB……..AQAB                       |
 |                       | (O) Optional, (M) Must |
 */
typedef struct tbc_provision_config
{
  tbc_provision_type_t provisionType; // Generates/Supplies credentials type. // Hardcode or device profile.
 
  const char *deviceName;           // Device name in TB        // Chip name + Chip id, e.g., "esp32-C8:D6:93:12:BC:01". Each device is different.
  const char *provisionDeviceKey;   // Provision device key     // Hardcode or device profile. Each model is different. 
  const char *provisionDeviceSecret;// Provision device secret  // Hardcode or device profile. Each model is different.

  const char *token;     // Access token for device             // Randomly generated. Each device is different.
  const char *clientId;  // Client id for device                // Randomly generated. Each device is different.
  const char *username;  // Username for device                 // Randomly generated. Each device is different.
  const char *password;  // Password for device                 // Randomly generated. Each device is different.
  const char *hash;      // Public key X509 hash for device     // Public key X509.    Each device is different.
} tbc_provision_config_t;

/**
 * ThingsBoard MQTT Client Helper OTA update type
 */
typedef enum
{
  TBCMH_OTAUPDATE_TYPE_FW = 0, /*!< F/W OTA update */
  TBCMH_OTAUPDATE_TYPE_SW      /*!< S/W OTA update */
} tbcmh_otaupdate_type_t;

//==== Callback ===============================================================

/**
 * @brief  Callback of connected ThingsBoard IoT Platform
 *
 * Notes:
 * - If you call tbcmh_connect(), this callback will be called
 *   when ThingsBoard IoT Platform is connected
 * - In this callback: Subsribe shared attributes update or server-side RPC, send attribues request and ... 
 *
 * @param client    ThingsBoard MQTT Client Helper handle. client param of tbcmh_connect()
 * @param context   context param
 *
 */
typedef void (*tbcmh_on_connected_t)(tbcmh_handle_t client, void *context);

/**
 * @brief  Callback of disconnected ThingsBoard IoT Platform
 *
 * Notes:
 * - If you call tbcmh_connect(), this callback will be called
 *   when ThingsBoard IoT Platform is disconnected
 * - In this callback: ... 
 *
 * @param client    ThingsBoard MQTT Client Helper handle. client param of tbcmh_connect()
 * @param context   context param
 *
 */
typedef void (*tbcmh_on_disconnected_t)(tbcmh_handle_t client, void *context);

/**
 * @brief  Callback when "Shared Attributes Update" is received 
 * from ThingsBoard IoT platform
 *
 * Notes:
 * - If you call tbcmh_attributes_subscribe() or tbcmh_attributes_subscribe_of_array(), 
 *   this callback will be called when you receive shared attributes updates 
 * - Parse and deal received json object in this callback
 *
 * @param client    ThingsBoard MQTT Client Helper handle. client param of tbcmh_attributes_subscribe()
 *                    or tbcmh_attributes_subscribe_of_array()
 * @param context   context param
 * @param object    shared attributes updated, possibly contains multiple shared attributes
 *
 * @return 2 if tbcmh_disconnect() or tbcmh_destroy() is called inside in this callback
 *         1 if tbcmh_attributes_unsubscribe() is called inside in this callback
 *         0 on otherwise
 */
typedef int  (*tbcmh_attributes_on_update_t)(
                                tbcmh_handle_t client,
                                void *context,
                                const cJSON *object);

/**
 * @brief  Callback when "Client-side Attributes & Shared Attributes Response" is received 
 * from ThingsBoard IoT platform
 *
 * Notes:
 * - If you call tbcmh_attributes_request(), tbcmh_clientattributes_request() 
 *   or tbcmh_sharedattributes_request(), this callback will be called
 *   when you receive client-side_attributes & shared attributes response
 * - Parse and deal received json object in this callback
 *
 * @param client            ThingsBoard MQTT Client Helper handle. client param of tbcmh_attributes_request()
 *                              or tbcmh_clientattributes_request() or tbcmh_sharedattributes_request()
 * @param context           context param 
 * @param client_attributes client-side attributes response, possibly contains multiple client-side attributes
 * @param shared_attributes shared attributes response, possibly contains multiple shared attributes
 *
 */
typedef void (*tbcmh_attributes_on_response_t)(
                                tbcmh_handle_t client,
                                void *context,
                                const cJSON *client_attributes,
                                const cJSON *shared_attributes);

/**
 * @brief  Callback when Client-side Attributes & Shared Attributes response is Timeout 
 * from ThingsBoard IoT platform
 *
 * Notes:
 * - When you call tbcmh_attributes_request(), tbcmh_clientattributes_request() 
 *   or tbcmh_sharedattributes_request(), this callback will be called
 *   when client-side_attributes & shared attributes response is timeout
 * - Parse and deal timeout evennt in this callback
 *
 * @param client    ThingsBoard MQTT Client Helper handle. client param of tbcmh_attributes_request()
 *                      or tbcmh_clientattributes_request() or tbcmh_sharedattributes_request()
 * @param context   context param 
 *
 * @return 2            if tbcmh_disconnect() or tbcmh_destroy() is called inside in this callback
 *         0/ESP_OK     on success
 *         -1/ESP_FAIL  on failure
 */
typedef tbc_err_t (*tbcmh_attributes_on_timeout_t)(
                                tbcmh_handle_t client,
                                void *context);

/**
 * @brief  Callback when "Server-side RPC Request" is received from ThingsBoard IoT platform
 *
 * Notes:
 * - If you call tbcmh_serverrpc_subscribe(), this callback will be called
 *   when you receive server-side RPC 
 * - Parse and deal received rpc_params in this callback
 * - Free return value(rpc_results) by caller/(this library)!
 *
 * @param client     ThingsBoard MQTT Client Helper handle. client param of tbcmh_serverrpc_subscribe()
 * @param context    context param
 * @param request_id 
 * @param method     rpc method name
 * @param rpc_params rpc params
 *
 * @return NULL if it is one-way server-side RPC without response.
 *              It MUST returns NULL if calling tbcmh_disconnect() or tbcmh_destroy() inside it!
 *         A rpc_results (cJSON object) if it is two-way server-side RPC with response,
 *              Free rpc_results by caller/(this library)!
 */
typedef tbcmh_rpc_results_t *(*tbcmh_serverrpc_on_request_t)(
                                tbcmh_handle_t client,
                                void *context, uint32_t request_id,
                                const char *method,
                                const tbcmh_rpc_params_t *rpc_params);

/**
 * @brief  Callback when two-way "Client-side RPC Response" is received 
 * from ThingsBoard IoT platform
 *
 * Notes:
 * - If you call tbcmh_twoway_clientrpc_request(), this callback will be called
 *   when you receive client-side RPC response
 * - Parse and deal received rpc_results in this callback
 *
 * @param client    ThingsBoard MQTT Client Helper handle. client param of 
 *                      tbcmh_twoway_clientrpc_request()
 * @param context   context param 
 * @param method     rpc method name
 * @param results    rpc results in client-side RPC response
 *
 * @return 2 if tbcmh_disconnect() or tbcmh_destroy() is called inside in this callback
 *         1 if tbcmh_sharedattributes_unregister() or tbcmh_attributes_unsubscribe() 
 *              is called inside in this callback
 *         0 on otherwise
 */
typedef void (*tbcmh_clientrpc_on_response_t)(
                                tbcmh_handle_t client,
                                void *context,
                                const char *method,
                                const tbcmh_rpc_results_t *results);

/**
 * @brief  Callback when two-way Client-side RPC response is Timeout 
 * from ThingsBoard IoT platform
 *
 * Notes:
 * - If you call tbcmh_twoway_clientrpc_request(), this callback will be called
 *   when  client-side RPC response is timeout
 * - Parse and deal timeout event in this callback
 *
 * @param client    ThingsBoard MQTT Client Helper handle. client param of 
 *                      tbcmh_twoway_clientrpc_request()
 * @param context   context param 
 * @param method    rpc method name
 *
 * @return 2 if tbcmh_disconnect() or tbcmh_destroy() is called inside in this callback
 *         0/ESP_OK on success
 *         -1/ESP_FAIL on failure
 */
typedef int (*tbcmh_clientrpc_on_timeout_t)(
                                tbcmh_handle_t client,
                                void *context,
                                const char *method);

/**
 * @brief  Callback when "Provision Response" is received 
 * from ThingsBoard IoT platform
 *
 * Notes:
 * - If you call tbcmh_provision_request(), this callback will be called
 *   when you receive provision response
 * - Parse and deal received credentials in this callback
 *
 * @param client        ThingsBoard MQTT Client Helper handle. client param of 
 *                          tbcmh_provision_request()
 * @param context       context param 
 * @param credentials   it in received provision response
 *
 */
typedef void (*tbcmh_provision_on_response_t)(
                                tbcmh_handle_t client,
                                void *context,
                                const tbc_transport_credentials_config_t *credentials);

/**
 * @brief  Callback when Rrovision response is Timeout 
 * from ThingsBoard IoT platform
 *
 * Notes:
 * - If you call tbcmh_provision_request(), this callback will be called
 *   when provision response is timeout
 * - Parse and deal timeout event in this callback
 *
 * @param client        ThingsBoard MQTT Client Helper handle. client param of 
 *                          tbcmh_provision_request()
 * @param context       context param 
 * @param credentials   it in received provision response
 *
 * @return 2 if tbcmh_disconnect() or tbcmh_destroy() is called inside in this callback
 *         0/ESP_OK on success
 *         -1/ESP_FAIL on failure
 *
 */
typedef int (*tbcmh_provision_on_timeout_t)(tbcmh_handle_t client, void *context);

/**
 * @brief  Callback of get current F/W or S/W title
 *
 * Notes:
 * - If you call tbcmh_otaupdate_subscribe(), this callback will be called
 *   before sending F/W or S/W shared attributes request
 * - Don't call TBCMH API in this callback!
 *
 * @param context       context param of tbcmh_otaupdate_subscribe()
 * @param credentials   it in received provision response
 *
 */
typedef const char* (*tbcmh_otaupdate_on_get_current_title_t)(void *context);

/**
 * @brief  Callback of get current F/W or S/W version
 *
 * Notes:
 * - If you call tbcmh_otaupdate_subscribe(), this callback will be called
 *   before sending F/W or S/W shared attributes request
 * - Don't call TBCMH API in this callback!
 *
 * @param context       context param of tbcmh_otaupdate_subscribe()
 * @param credentials   it in received provision response
 *
 */
typedef const char* (*tbcmh_otaupdate_on_get_current_version_t)(void *context);

/**
 * @brief  Callback if F/W or S/W upgrade completed or aborted
 *
 * Notes:
 * - If you call tbcmh_otaupdate_subscribe(), this callback will be called
 *   after F/W or S/W upgrade completed or aborted
 * - Don't call TBCMH API in this callback!
 *
 * @param context   context param of tbcmh_otaupdate_subscribe()
 * @param result    true: upgrade successful, false: updated failed
 *
 */
typedef void (*tbcmh_otaupdate_on_updated_t)(void *context, bool result);

//==== MQTT connection =========================================================

/**
 * @brief creates ThingsBoard client mqtt handle
 *
 * @return tbcmh_handle_t if successfully created, NULL on error
 */
tbcmh_handle_t tbcmh_init(void);

/**
 * @brief destroys ThingsBoard client mqtt handle
 *
 * @param client   ThingsBoard MQTT Client Helper handle
 */
void tbcmh_destroy(tbcmh_handle_t client);

/**
 * @brief connects to ThingsBoard Platform
 *
 * @param client    ThingsBoard MQTT Client Helper handle
 * @param config    esay transport configuration
 * @param context    
 * @param on_connected    callback of connected
 * @param on_disconnected callback of disconnected   
 *
 * @return true on successful, faiure on failure
 */
bool tbcmh_connect_using_url(tbcmh_handle_t client,
                                const tbc_transport_config_esay_t *config,
                                void *context,
                                tbcmh_on_connected_t on_connected,
                                tbcmh_on_disconnected_t on_disconnected);

/**
 * @brief connects to ThingsBoard Platform
 *
 * @param client    ThingsBoard MQTT Client Helper handle
 * @param config    transport configuration
 * @param context    
 * @param on_connected    callback of connected
 * @param on_disconnected callback of disconnected   
 *
 * @return true on successful, false on failure
 */
bool tbcmh_connect(tbcmh_handle_t client,
                                const tbc_transport_config_t *config,
                                void *context,
                                tbcmh_on_connected_t on_connected,
                                tbcmh_on_disconnected_t on_disconnected);

/**
 * @brief disconnects from ThingsBoard Platform
 *
 * @param client    ThingsBoard MQTT Client Helper handle
 *
 */
void tbcmh_disconnect(tbcmh_handle_t client);

/**
 * @brief Is it connected to ThingsBoard Platform
 *
 * @param client    ThingsBoard MQTT Client Helper handle
 *
 * @return true on connected, false on otherwise
 */
bool tbcmh_is_connected(tbcmh_handle_t client);

/**
 * @brief Has it events in event queue?
 *
 * @param client    ThingsBoard MQTT Client Helper handle
 *
 * @return true or false
 */
bool tbcmh_has_events(tbcmh_handle_t client);

/**
 * @brief Has it events in event queue?
 *
 * @param client    ThingsBoard MQTT Client Helper handle
 *
 * Notes:
 * - receive events from queue, then parse and deal.
 *
 */
void tbcmh_run(tbcmh_handle_t client);

//==== Publish Telemetry time-series data =====================================
/**
 * @brief Publish telemetry data to ThingsBoard platform
 *
 * Notes:
 * - It should be called after the MQTT connection is established
 * - A ThingsBoard MQTT Protocol message example:
 *      Topic: 'v1/devices/me/telemetry'
 *      Data:  '{"key1":"value1", "key2":true, "key3": 3.0, "key4": 4}', '[{"key1":"value1"}, {"key2":true}]'
 *
 * @param client     ThingsBoard MQTT Client Helper handle
 * @param telemetry  telemetry. example: {"key1":"value1", "key2":true, "key3": 3.0, "key4": 4}, (字符串要符合 json 数据格式)
 * @param qos        qos of publish message, 0 or 1
 * @param retain     ratain flag
 *
 * @return message_id of the publish message (for QoS 0 message_id will always be zero) on success.
 *         0 if cannot publish
 *        -1/ESP_FAIL on error
 */
int tbcmh_telemetry_upload(tbcmh_handle_t client,
                                const char *telemetry,
                                int qos/*= 1*/,
                                int retain/*= 0*/);

/**
 * @brief Publish telemetry data to ThingsBoard platform
 *
 * Notes:
 * - It should be called after the MQTT connection is established
 * - A ThingsBoard MQTT Protocol message example:
 *      Topic: 'v1/devices/me/telemetry'
 *      Data:  '{"key1":"value1", "key2":true, "key3": 3.0, "key4": 4}', '[{"key1":"value1"}, {"key2":true}]'
 *
 * @param client     ThingsBoard MQTT Client Helper handle
 * @param object     cJSON object or array of cJSON object
 * @param qos        qos of publish message, 0 or 1
 * @param retain     ratain flag
 *
 * @return message_id of the publish message (for QoS 0 message_id will always be zero) on success.
 *         0 if cannot publish
 *        -1/ESP_FAIL on error
 */
int tbcmh_telemetry_upload_ex(tbcmh_handle_t client,
                                const tbcmh_value_t *object,
                                int qos/*= 1*/,
                                int retain/*= 0*/);

//==== Publish client-side device attributes to the server=====================
/**
 * @brief Client to send a 'Attributes' publish message to ThingsBoard platform
 *
 * Notes:
 * - It should be called after the MQTT connection is established
 * - It is thread safe, please refer to `esp_mqtt_client_subscribe` for details
 * - A ThingsBoard MQTT Protocol message example:
 *      Topic: 'v1/devices/me/attributes'
 *      Data:  '{"attribute1":"value1", "attribute2":true, "attribute3":42.0, "attribute4":73}'
 *
 * @param client        ThingsBoard MQTT Client Helper handle
 * @param attributes    attributes. example: {"attribute1":"value1", "attribute2":true, "attribute3":42.0, "attribute4":73} (字符串要符合 json 数据格式)
 * @param qos           qos of publish message
 * @param retain        ratain flag
 *
 * @return message_id of the subscribe message on success
 *         0 if cannot publish
 *        -1 if error
 */
int tbcmh_attributes_update(tbcmh_handle_t client,
                                const char *attributes,
                                int qos /*= 1*/,
                                int retain /*= 0*/);

/**
 * @brief Client to send a 'Attributes' publish message to ThingsBoard platform
 *
 * Notes:
 * - It should be called after the MQTT connection is established
 * - It is thread safe, please refer to `esp_mqtt_client_subscribe` for details
 * - A ThingsBoard MQTT Protocol message example:
 *      Topic: 'v1/devices/me/attributes'
 *      Data:  '{"attribute1":"value1", "attribute2":true, "attribute3":42.0, "attribute4":73}'
 *
 * @param client        ThingsBoard MQTT Client Helper handle
 * @param attributes    attributes. example: {"attribute1":"value1", "attribute2":true, "attribute3":42.0, "attribute4":73} (字符串要符合 json 数据格式)
 * @param qos           qos of publish message
 * @param retain        ratain flag
 *
 * @return message_id of the subscribe message on success
 *         0 if cannot publish
 *        -1 if error
 */
int tbcmh_attributes_update_ex(tbcmh_handle_t client,
                                tbcmh_value_t *object,
                                int qos/*= 1*/,
                                int retain/*= 0*/);

//==== Subscribe to shared device attribute updates from the server============

/**
 * @brief Subscribe to shared device attribute updates from the server
 *
 * Notes:
 * - It may be called before the MQTT connection is established
 *
 * @param client        ThingsBoard MQTT Client Helper handle
 * @param context
 * @param on_update     calllback of shared device attributes update
 * @param count         count of keys
 * @param keys          keys of shared device attributes
 * 
 * @return subscribe_id on success
 *         -1/ESP_FAIL on failure
 */
int tbcmh_attributes_subscribe(tbcmh_handle_t client,
                                void *context,
                                tbcmh_attributes_on_update_t on_update,
                                int count,
                                /*const char *key,*/...);

/**
 * @brief Subscribe to shared device attribute updates from the server
 *
 * Notes:
 * - It may be called before the MQTT connection is established
 *
 * @param client        ThingsBoard MQTT Client Helper handle
 * @param context
 * @param on_update     calllback of shared device attributes update
 * @param count         count of keys
 * @param keys          array of shared device attributes
 * 
 * @return subscribe_id on success
 *         -1/ESP_FAIL on failure
 */
int tbcmh_attributes_subscribe_of_array(
                                tbcmh_handle_t client,
                                void *context,
                                tbcmh_attributes_on_update_t on_update,
                                int count, const char *keys[]);

/**
 * @brief Unsubscribe to shared device attribute updates from the server
 *
 * Notes:
 * - It may be called before the MQTT connection is established
 *
 * @param client        ThingsBoard MQTT Client Helper handle
 * @param subscribe_id  suscribe id
 * 
 * @return 0/ESP_OK on success
 *         -1/ESP_FAIL on failure
 */
tbc_err_t tbcmh_attributes_unsubscribe(
                                tbcmh_handle_t client,
                                int subscribe_id);

//==== Request client-side or shared device attributes from the server ========
/**
 * @brief Request client-side or shared device attributes from the server
 *
 * Notes:
 * - It should be called after the MQTT connection is established
 *
 * @param client        ThingsBoard MQTT Client Helper handle
 * @param context
 * @param on_response   calllback of device attributes response
 * @param on_timeout    calllback of device attributes timeout event
 * @param client_keys   client_keys, like "abc, efg, xyz"
 * @param shared_keys   shared_keys, like "abc, efg, xyz"
 * 
 * @return 0/ESP_OK on successful
 *         -1/ESP_FAIL on otherwise
 */
tbc_err_t tbcmh_attributes_request(
                                tbcmh_handle_t client,
                                void *context,
                                tbcmh_attributes_on_response_t on_response,
                                tbcmh_attributes_on_timeout_t on_timeout,
                                const char *client_keys,
                                const char *shared_keys);

/**
 * @brief Request client-side device attributes from the server
 *
 * Notes:
 * - It should be called after the MQTT connection is established
 *
 * @param client        ThingsBoard MQTT Client Helper handle
 * @param context
 * @param on_response   calllback of device attributes response
 * @param on_timeout    calllback of device attributes timeout event
 * @param client_keys   client_keys, like "abc, efg, xyz"
 * 
 * @return 0/ESP_OK on successful
 *         -1/ESP_FAIL on otherwise
 */
tbc_err_t tbcmh_clientattributes_request(
                                tbcmh_handle_t client,
                                void *context,
                                tbcmh_attributes_on_response_t on_response,
                                tbcmh_attributes_on_timeout_t on_timeout,
                                int count,
                                /*const char *key,*/...);

/**
 * @brief Request shared device attributes from the server
 *
 * Notes:
 * - It should be called after the MQTT connection is established
 *
 * @param client        ThingsBoard MQTT Client Helper handle
 * @param context
 * @param on_response   calllback of device attributes response
 * @param on_timeout    calllback of device attributes timeout event
 * @param shared_keys   shared_keys, like "abc, efg, xyz"
 * 
 * @return 0/ESP_OK on successful
 *         -1/ESP_FAIL on otherwise
 */
tbc_err_t tbcmh_sharedattributes_request(
                                tbcmh_handle_t client,
                                void *context,
                                tbcmh_attributes_on_response_t on_response,
                                tbcmh_attributes_on_timeout_t on_timeout,
                                int count, /*const char *key,*/...);

//==== Server-side RPC ========================================================

/**
 * @brief Subscribe to server-side RPC from the server
 *
 * Notes:
 * - It may be called before the MQTT connection is established
 *
 * @param client        ThingsBoard MQTT Client Helper handle
 * @param method        RPC method name
 * @param context
 * @param on_request    calllback of server-side RPC request
 * 
 * @return  0/ESP_OK on success
 *         -1/ESP_FAIL on failure
 */
tbc_err_t tbcmh_serverrpc_subscribe(
                                tbcmh_handle_t client,
                                const char *method,
                                void *context,
                                tbcmh_serverrpc_on_request_t on_request);

/**
 * @brief Subscribe to server-side RPC from the server
 *
 * Notes:
 * - It may be called before the MQTT connection is established
 *
 * @param client        ThingsBoard MQTT Client Helper handle
 * @param method        RPC method name
 * 
 * @return  0/ESP_OK on success
 *         -1/ESP_FAIL on failure
 */
tbc_err_t tbcmh_serverrpc_unsubscribe(
                                tbcmh_handle_t client,
                                const char *method);

//==== Client-side RPC ========================================================

/**
 * @brief Send one-way client-side RPC request to the server
 *
 * Notes:
 * - It should be called after the MQTT connection is established
 *
 * @param client        ThingsBoard MQTT Client Helper handle
 * @param method        RPC method name
 * @param params        RPC params
 * 
 * @return  0/ESP_OK on successful
 *         -1/ESP_FAIL on otherwise
 */
tbc_err_t tbcmh_oneway_clientrpc_request(
                                tbcmh_handle_t client,
                                const char *method,
                                const tbcmh_rpc_params_t *params);

/**
 * @brief Send two-way client-side RPC request to the server
 *
 * Notes:
 * - It should be called after the MQTT connection is established
 *
 * @param client        ThingsBoard MQTT Client Helper handle
 * @param method        RPC method name
 * @param params        RPC params
 * @param context
 * @param on_response   calllback of RPC response
 * @param on_timeout    calllback of RPC timeout event
 * 
 * @return  0/ESP_OK on successful
 *         -1/ESP_FAIL on otherwise
 */
tbc_err_t tbcmh_twoway_clientrpc_request(
                                tbcmh_handle_t client,
                                const char *method,
                                const tbcmh_rpc_params_t *params,
                                void *context,
                                tbcmh_clientrpc_on_response_t on_response,
                                tbcmh_clientrpc_on_timeout_t on_timeout);

//==== initiate claiming device using device-side key scenario ================

/**
 * @brief Send message of initiate claiming device to the server
 *
 * Notes:
 * - It should be called after the MQTT connection is established
 * - See https://thingsboard.io/docs/user-guide/claiming-devices/#device-claiming-scenarios
 *
 * @param client        ThingsBoard MQTT Client Helper handle
 * @param secret_key    adds security to the claiming process
 * @param duration_ms   determines the expiration of claiming time
 * 
 * @return  0/ESP_OK on successful
 *         -1/ESP_FAIL on otherwise
 */
tbc_err_t tbcmh_claiming_device_initiate_using_device_side_key(
                                tbcmh_handle_t client,
                                const char *secret_key,
                                uint32_t *duration_ms);

//==== Device provisioning ====================================================
/**
 * @brief Send device provisioning request to the server
 *
 * Notes:
 * - It should be called after the MQTT connection is established
 *
 * @param client        ThingsBoard MQTT Client Helper handle
 * @param config
 * @param context
 * @param on_response   calllback of device provisioning response
 * @param on_timeout    calllback of device provisioning timeout event
 * 
 * @return  0/ESP_OK on successful
 *         -1/ESP_FAIL on otherwise
 */
tbc_err_t tbcmh_provision_request(
                                tbcmh_handle_t client,
                                const tbc_provision_config_t *config,
                                void *context,
                                tbcmh_provision_on_response_t on_response,
                                tbcmh_provision_on_timeout_t on_timeout);

//==== Firmware update ========================================================
/**
 * @brief Subscribe F/W or S/W OTA updates to the server
 *
 * Notes:
 * - It may be called before the MQTT connection is established
 *
 * @param client                    ThingsBoard MQTT Client Helper handle
 * @param ota_description           descripion
 * @param ota_type                  FW/TBCMH_OTAUPDATE_TYPE_FW or SW/TBCMH_OTAUPDATE_TYPE_SW
 * @param context_user              context           
 * @param on_get_current_title      callback of getting current F/W or S/W OTA title 
 * @param on_get_current_version    callback of getting current F/W or S/W OTA version
 * @param on_updated                callback of F/W or S/W upgrade completed or aborted
 * 
 * @return  0/ESP_OK on success
 *         -1/ESP_FAIL on failure
 */
tbc_err_t tbcmh_otaupdate_subscribe(
                                tbcmh_handle_t client,
                                const char *ota_description,  // TODO: remove it!
                                tbcmh_otaupdate_type_t ota_type,
                                void *context_user,
                                tbcmh_otaupdate_on_get_current_title_t on_get_current_title,
                                tbcmh_otaupdate_on_get_current_version_t on_get_current_version,
                                tbcmh_otaupdate_on_updated_t on_updated);

/**
 * @brief Unsubscribe F/W or S/W OTA updates from the server
 *
 * Notes:
 * - It may be called before the MQTT connection is established
 *
 * @param client                ThingsBoard MQTT Client Helper handle
 * @param ota_description       Descripion, see ota_description param of tbcmh_otaupdate_subscribe()
 * 
 * @return  0/ESP_OK on success
 *         -1/ESP_FAIL on failure
 */
tbc_err_t tbcmh_otaupdate_unsubscribe(
                                tbcmh_handle_t client,
                                const char *ota_description);

#ifdef __cplusplus
}
#endif //__cplusplus

#endif

